from Goldenberry.optimization.ga.GbCrossoverMgr.CrossoverStrategy import CrossoverStrategy
import random as ran
import numpy as np

class OnePointRealCrossover(CrossoverStrategy):
    def __init__(self):
        self.name='OnePointRealCrossover'

    def cross(self, parents):
        """Cross the parents using one point crossover.
    
        :param parents: array list of parents individual to cross, each parent is a GbIndividual
        :returns: two numpy array genotype1, genotype2 generated, corresponding to the genotype of the new individuals
        """
        pcut = int(ran.random()*len(parents[0].genotype))
        genotype1 = np.concatenate((parents[0].genotype[:pcut],parents[1].genotype[pcut:]))
        genotype2 = np.concatenate((parents[1].genotype[:pcut],parents[0].genotype[pcut:]))
        #PILAS, aca esta devolviendo el genotipo toca decodificarlo y calcular la funcion de costo y cuando se tenga todo hay si toca crear el individuo
        return genotype1, genotype2

class TwoPointRealCrossover(CrossoverStrategy):
    def __init__(self):
        self.name='TwoPointRealCrossover'

    def cross(self, parents):
        """Cross the parents using multiple point crossover.
    
        :param parents: array list of parents individual to cross, each parent is a GbIndividual
        :returns: two numpy array genotype1, genotype2 generated,  corresponding to the genotype of the new individuals
        """
        pts_cut = ran.randint(1, len(parents[0].genotype)-1), ran.randint(1, len(parents[0].genotype)-1)#np.random.random_integers(1,len(parents[0].genotype)-1, 2)
        pcut_one, pcut_two = np.amin(pts_cut), np.amax(pts_cut)
        genotype1 = np.concatenate((parents[0].genotype[:pcut_one],parents[1].genotype[pcut_one:pcut_two], parents[0].genotype[pcut_two:]))
        genotype2 = np.concatenate((parents[1].genotype[:pcut_one],parents[0].genotype[pcut_one:pcut_two], parents[1].genotype[pcut_two:]))
        return genotype1, genotype2

class UniformArithmeticalCrossoverAX(CrossoverStrategy):
    """Uniform AX Crossover."""
    def __init__(self):
        self.name='UniformArithmeticalCrossoverAX'

    def cross(self, parents):
        """Cross the parents using uniform arithmetic crossover.
       
        :param parents: array list of parents individual to cross
        :returns: offspring generated
        """
        genotype1, genotype2 = self._linearly_combine(parents[0].genotype, parents[1].genotype)
        return genotype1, genotype2

class BlendCrossoverBLXA(CrossoverStrategy):
    """BLXA Crossover."""
    def __init__(self):
        self.name='BlendCrossoverBLXA'

    def cross(self, parents):
        """Cross the parents using blend-alpha crossover. 
       
        :param parents: array list of parents individual to cross
        :returns: offspring generated
        """
        alpha = ran.random()
        delta = parents[0].genotype - parents[1].genotype
        parentp1 = parents[0].genotype + alpha * delta
        parentp2 = parents[1].genotype - alpha * delta
        genotype1, genotype2 = self._linearly_combine(parentp1, parentp2)
        return genotype1, genotype2

class BlendCrossoverBLXAB(CrossoverStrategy):
    """BLXAB Crossover."""

    def __init__(self):
        self.name='BlendCrossoverBLXAB'

    def cross(self, parents):
        """Cross the parents using blend-alpha.beta crossover.
       
        :param parents: array list of parents individual to cross
        :returns: offspring generated
        """
        alpha = ran.random()
        beta = ran.random()
        delta = parents[0].genotype - parents[1].genotype
        parentp1 = parents[0].genotype + alpha * delta
        parentp2 = parents[1].genotype - beta * delta
        genotype1, genotype2 = self._linearly_combine(parentp1, parentp2)
        return genotype1, genotype2

class HeuristicCrossoverWHX(CrossoverStrategy):
    """WHX Crossover."""
    def __init__(self):
        self.name='HeuristicCrossoverWHX'

    def cross(self, parents):
        """Cross the parents using heuristic crossover.
       
        :param parents: array list of parents individual to cross
        :returns: offspring generated
        """
        eta = ran.random()
        if parents[0].cost >=  parents[1].cost:
           delta = parents[0].genotype - parents[1].genotype
           parentp = parents[0].genotype + eta * delta
           genotype1, genotype2 = self._linearly_combine(parents[0].genotype, parentp)
        else: 
            delta = parents[1].genotype - parents[0].genotype
            parentp = parents[1].genotype + eta * delta
            genotype1, genotype2 = self._linearly_combine(parents[1].genotype, parentp)
        return genotype1, genotype2
